<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 模拟已有的属性和属性值的数组，以及一个被用于存储“将要被添加或更新的属性的数据”的对象
        let array = [{ attrName1: 1, attrValueList: [1, 2, 3] }, { attrName2: 2, attrValueList: [4, 5, 6] }];
        let anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated = {
            attrName: '',
            attrValueList: [],
        }
        Object.assign(anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated, array[0]);
        console.log(anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated) // { attrName1: 1, attrValueList: [1, 2, 3] }
        anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated.attrValueList[0] = 10;
        console.log(anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated) // { attrName: "", attrName1: 1, attrValueList: [10, 2, 3] }
        console.log(array) // [{ attrName1: 1, attrValueList: [10, 2, 3] }, { attrName2: 2, attrValueList: [4, 5, 6] }]
        // 从控制台中输出的结果中可以看到，当“anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated.attrValueList[0]”被赋值为“10”时，“array”数组中的“attrValueList”数组中的第一项内容也被更新了（即“array.attrValueList[0]”的值也是“10”）。这是因为Object.assign()方法会将源对象的所有可枚举属性复制到目标对象中，
        // 并且如果目标对象中有同名属性，则会用源对象中的属性值覆盖它。因此，当我们修改anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated对象时，
        // 实际上也修改了array数组中第一个对象的引用。为了避免出现这种情况，我们可以使用“深拷贝”（例如通过“展开运算符”(即“...”)来创建一个新的对象副本）
        // 以下内容是文心快码对上面这段代码的解释：
        /* # 代码解释

## 1. HTML 结构

该代码段是一个简单的 HTML 文档，包含基本的 HTML 结构：`<html>`, `<head>`, 和 `<body>` 标签。`<head>` 标签内定义了文档的字符集、视口设置和标题。`<body>` 标签内包含一个 `<script>` 标签，用于执行 JavaScript 代码。

## 2. JavaScript 代码

### 2.1 变量定义

- `array`：一个包含两个对象的数组，每个对象代表一个属性，具有 `attrName`（属性名）和 `attrValueList`（属性值列表）属性。但这里有一个问题，数组中的对象实际上使用的是 `attrName1` 而不是 `attrName` 作为属性名。
- `anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated`：一个对象，用于存储将要被添加或更新的属性的数据，包含 `attrName` 和 `attrValueList` 属性。

### 2.2 使用 `Object.assign`

- `Object.assign` 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
- 在此代码中，`Object.assign(anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated, array[0]);` 将 `array` 数组中的第一个对象的属性复制到 `anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated` 对象中。

### 2.3 修改对象属性

- `anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated.attrValueList[0] = 10;` 修改了 `anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated` 对象中 `attrValueList` 数组的第一项。

### 2.4 控制台输出

- 通过 `console.log` 输出 `anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated` 和 `array` 的内容，观察修改后的效果。

### 2.5 问题与现象

- 当修改 `anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated.attrValueList[0]` 时，`array` 数组中的第一个对象的 `attrValueList` 数组的第一项也被修改了。这是因为 `Object.assign` 只是浅拷贝了对象属性，`attrValueList` 数组在 `anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated` 和 `array[0]` 中引用的是同一个数组实例。

## 3. 深拷贝与浅拷贝

- **浅拷贝**：只复制对象的第一层属性，如果属性是引用类型（如数组或对象），则复制的是引用而非对象本身。
- **深拷贝**：递归地复制对象及其所有层级属性，确保所有引用类型属性都被复制为新的实例。

### 3.1 如何避免浅拷贝的问题

- 使用深拷贝来避免上述问题。例如，可以使用展开运算符（`...`）和 `JSON.parse`/`JSON.stringify` 方法（尽管这种方法有其局限性，如无法处理函数、`undefined`、`Symbol` 等）来实现深拷贝。

```javascript
let deepCopiedObject = { ...array[0], attrValueList: [...array[0].attrValueList] };
Object.assign(anObjectUsedToStoreTheDataOfAnAttributeThatBeAddedOrUpdated, deepCopiedObject);
```

或者，使用库如 Lodash 的 `_.cloneDeep` 方法来进行深拷贝。

## 4. 结论

这段代码演示了 `Object.assign` 的浅拷贝特性以及由此引发的问题。在需要复制对象并修改其属性而不影响原对象时，应使用深拷贝方法。 */
    </script>
</body>

</html>